#ifndef TIMESTRUCTURE_H
#define TIMESTRUCTURE_H

#include <QtGui>
#include <QApplication>


#define _SEPA_ "|"




class CDay
{
    public:
    enum { MAGICNUMBER = 0xFFAAFFAA, VERSION = 8 };
    CDay() {
    dax = QDate::currentDate();
    note = "";
    res = 0;
    mex = 0;
    }
    operator QVariant() const {
    return QVariant::fromValue(*this);
    }
    bool having_data()
    {
       if (res !=0 || note.size() !=0) {
         return true;
       } else {
         return false;
       }
    }
    QIcon createColorToolButtonIcon( int setmodus )
    {
    QPixmap pixmap(50, 50);
    pixmap.fill(BG(setmodus));
    QPainter painter(&pixmap);
    return QIcon(pixmap);
    }
    
    QIcon NotaVedi()
    {
    QPixmap pixmap(5,5);
    pixmap.fill(QColor(Qt::blue));
    QPainter painter(&pixmap);
    return QIcon(pixmap);
    }

    QColor BG( int setmodus ) 
    {
         /* reservation modus    0= libero / 1= prenotato / 2= prenotato provvisorio / 3= riservato / 10 = chiuso / */
      
         if ( setmodus == 1 ) {
					 return QColor("#ffb4a7");
				 } else if ( setmodus == 2 ) {
					 return QColor("#ffcf97");
				 } else if ( setmodus == 3 ) {
					 return QColor("#ff0000");
				 } else if ( setmodus == 10 ) {
					 return QColor("#bfbfbf");
				 } else {
           return QColor(Qt::white);
         }
    }
    QColor FC( int setmodus ) 
    {
      /* reservation modus    0= libero / 1= prenotato / 2= prenotato provvisorio / 3= riservato / 10 = chiuso / */
      
         if ( setmodus == 1 ) {
					 return QColor(Qt::darkBlue);
				 } else if ( setmodus == 2 ) {
					 return QColor(Qt::darkBlue);
				 } else if ( setmodus == 3 ) {
					 return QColor(Qt::white);
				 } else if ( setmodus == 10 ) {
					 return QColor(Qt::white);
				 } else {
           return QColor(Qt::darkBlue);
         }
    }
    void set( int y, int m, int d , int modus = 1 ) 
    {
    dax = QDate(y,m,d);
    mex = qBound(1,modus,10);
    }
    /*
    QString tostring()
    {
      if (dax.isValid() {
      return dax.toString("dd.MM.yyyy");
      } else {
      return QString();
      }
    }
    */
    bool real() {
      if (mex == 10) {
      return true;
      } else {
      return false;
      }
    }
    int day() const  {
      return dax.day();
    }
    uint stop() const 
    {
       if (xstop.isValid()) {
       return xstop.toTime_t();
       } else {
       return 0;
       }
    }
    uint start() const
    {
       if (xstart.isValid()) {
       return xstart.toTime_t();
       } else {
       return 0;
       }
    }
     CDay& operator=( const CDay& d )
    {
      qDebug() << "operator  CDay->" << d.day();
      
      mex = d.mex;
      res = d.res;
      dax = d.dax;
      xstop = d.xstop;
      xstart = xstart;
      note = d.note;
      data = d.data;
      return *this;
    }
    
    /* vars permanent */
    int mex;  /* open status active month date or not !!!! */
    int res;  /* reservation modus    0= libero / 1= prenotato / 2= prenotato provvisorio / 3= riservato / 10 = chiuso / */
    QDate dax;
    QDateTime xstop;
    QDateTime xstart;
    QByteArray data;  /* reserve! image or so ... */
    QString note; 
};

Q_DECLARE_METATYPE(CDay);

inline QDebug operator<<(QDebug debug, const CDay& tline)
{
	debug.nospace() << "CDay(mex()" 
		    << tline.mex << ",res()" 
        << tline.res << ",date()" 
        << tline.dax << "," 
        << tline.xstop << ","
        << tline.xstart << ","
        << tline.data << ","    
        << tline.note << ")";
	return debug.space();
}

inline QDataStream& operator<<(QDataStream& out, const CDay& udoc)
{
    out << udoc.mex;
    out << udoc.res;
    out << udoc.dax;
    out << udoc.xstop;
    out << udoc.xstart;
    out << udoc.data;
    out << udoc.note;
    return out;
}

inline QDataStream& operator>>(QDataStream& in, CDay& udoc)
{
  in >> udoc.mex;
  in >> udoc.res;
  in >> udoc.dax;
  in >> udoc.xstop;
  in >> udoc.xstart;
  in >> udoc.data;
  in >>udoc.note;
  return in;
}


class CMonths
{
  public:
  enum { MAGICNUMBER = 0xFFAAFFAA, VERSION = 3 };
  CMonths() {
  me = 0;
  anno = 0;
  WeekfirstM = 0;
  SummDay = 0;
  WeekfirstM = 0;
  }
  void init( int y, int m )
  {
    me = m;
    anno = y;
    const int NextYear = y + 1;
    ram_day.clear();
    QDate first(y,m,1);
    QDate next_Y(NextYear,1,1);
    WeekfirstM = first.dayOfWeek() - 1;
    QDateTime day_1(first);   
    QDateTime day_last = day_1.addMonths(1); 
    WeeklastM = day_last.date().dayOfWeek();
    SummDay = day_1.daysTo(day_last);
      /////////////// qDebug() << "#################################"; 
        /* prepend day before months !*/
        if (first.dayOfWeek() !=1) {
            int prepend_da = first.dayOfWeek() - 1;
            ///////////////qDebug() << " prepend_da  " << prepend_da << " first.dayOfWeek() " << first.dayOfWeek();
            if (prepend_da == 1) {
              ram_day.append(day_1.addDays(-1).date());
            } else if (prepend_da == 2) {
              ram_day.append(day_1.addDays(-2).date());
              ram_day.append(day_1.addDays(-1).date());
            } else if (prepend_da == 3) {
              ram_day.append(day_1.addDays(-3).date());
              ram_day.append(day_1.addDays(-2).date());
              ram_day.append(day_1.addDays(-1).date());
            } else if (prepend_da == 4) {
              ram_day.append(day_1.addDays(-4).date());
              ram_day.append(day_1.addDays(-3).date());
              ram_day.append(day_1.addDays(-2).date());
              ram_day.append(day_1.addDays(-1).date());
            } else if (prepend_da == 5) {
              ram_day.append(day_1.addDays(-5).date());
              ram_day.append(day_1.addDays(-4).date());
              ram_day.append(day_1.addDays(-3).date());
              ram_day.append(day_1.addDays(-2).date());
              ram_day.append(day_1.addDays(-1).date());
            } else if (prepend_da == 6) {
              ram_day.append(day_1.addDays(-6).date());
              ram_day.append(day_1.addDays(-5).date());
              ram_day.append(day_1.addDays(-4).date());
              ram_day.append(day_1.addDays(-3).date());
              ram_day.append(day_1.addDays(-2).date());
              ram_day.append(day_1.addDays(-1).date());
            }
          
        }
     
        for (int dd = 1; dd <= SummDay; ++dd) {
             QDate sopra(y,m,dd);
             ram_day.append(sopra);
          
        }
        
       
        /* append day after months */
        int append = -1;
        while (ram_day.size() < 42) {
              append++;
              if (m == 12) {
                QDateTime newYears = QDateTime(next_Y); 
                ram_day.append(newYears.addDays(append).date());
                /////////qDebug() << " nuovo anno   " << m << " " << newYears.date().year();
              } else {
                //////qDebug() << " anno corrente  " << m;
                ram_day.append(day_last.addDays(append).date());
              }
              
          
              
          
          
              QDate coda = ram_day.last();
              WeeklastM = coda.dayOfWeek();      
        }
      
        
      ////////////QStringList sequenza;
                 ///////// sequenza.clear();
         ////////////QDate act = ram_day[i];
        ///////////sequenza.append(QString("%1-%2").arg(act.dayOfWeek()).arg(act.day()));
        clear_v();
        for (int i=0; i<ram_day.size(); i++) {
               QDate realdate = ram_day[i];
               int modus = 10;  /* active month */
               if (realdate.month() !=me) {
                 modus = 1;  /* outside month hidden */
               }
               CDay sday;
                    sday.set(realdate.year(),realdate.month(),realdate.day(),modus);
                    save_day.append(sday);
        }
        ram_day.clear();
      ////////////qDebug() << " m Name:  " << first.longMonthName(m);
      ////////////qDebug() << " WeeklastM  " << WeeklastM;
      //////////qDebug() << " SummDay  " << SummDay;
      ///////////qDebug() << " size() " << ram_day.size(); 
      /////////qDebug() << " sequenza " << sequenza;
      /////////////qDebug() << "#################################"; 
        
  }
  void clear_r()
  {
  ram_day.clear();
  }
  void clear_all()
  {
    ram_day.clear();
    save_day.clear();
  }
  void clear_v()
  {
  save_day.clear();
  }
  operator QVariant() const {
  return QVariant::fromValue(*this);
  }
  CMonths& operator=( CMonths d )
  {
      QList<CDay> li = d.list();
    
      me = d.me;
      anno = d.anno;
    
      for (int i=0; i<li.size(); i++) {
		  CDay placehere = li[i];
		  save_day.append(placehere);
	    }
   return *this;
  }
  int sum_day()
  {
    int ps = 0;
    QList<CDay> lines = list();
      for (int i=0; i<lines.size(); i++) {
		     CDay placehere = lines[i];
         if (placehere.real()) {
          ps++;
         }
	    }
    return ps;
  }
  QList<CDay> list()
  {
      return save_day;
  }
  int size()
  {
      return save_day.size();
  }
  void rewrite( QList<CDay> li )
  {
    ram_day.clear();
    save_day.clear();
    for (int i=0; i<li.size(); i++) {
      CDay giorno = li[i];
      save_day.append(giorno);
    }
    
  }
  void append( const CDay d ) 
  {
  save_day.append(d);
  }
  int year() {
  return anno;
  }
  int month() {
  return me;
  }
  QString name()
  {
   QStringList RTFmonth = QStringList() << "NULL" << "Jan" << "Feb" << "Mar" << "Apr" << "May" << "Jun" << "Jul" << "Aug" << "Sep" << "Oct" << "Nov" << "Dec";
   return RTFmonth.at(me);
  } 
  QStringList names()
  {
    QStringList nax;
    
    nax.append(name());
    
    for (int i=0; i<save_day.size(); i++) {
      CDay sday = save_day[i];
      QString Value  = "";
      if (sday.having_data()) {
        Value = "-X-";
      }
      nax.append(QString("%1%2").arg(sday.day()).arg(Value));
    }
    return nax;
  }
  
  int count_filled()
  {
    int daten = 0;
    for (int i=0; i<save_day.size(); i++) {
      CDay sday = save_day[i];
      QString Value  = "";
      if (sday.having_data()) {
        daten++;
      }
    }
    return daten;
  }
  
  int SummDay;
  int WeekfirstM;
  int WeeklastM;
  int xprepend;
  int xappend;
  QList<QDate> ram_day;
  /* save vars */
  int me;
  int anno;
  QList<CDay> save_day;
  
};




Q_DECLARE_METATYPE(CMonths);


inline QDataStream& operator<<(QDataStream& out,  CMonths& udoc)
{
    QList<CDay> lines = udoc.list();
    out << udoc.me;
    out << udoc.anno;
    for (int i=0; i<lines.size(); i++) {
		CDay placehere = lines[i];
		out << placehere;
	  }
    return out;
}

inline QDataStream& operator>>(QDataStream& in, CMonths& udoc)
{
    CDay set;
    in >> udoc.me;
    in >> udoc.anno;
    while (!in.atEnd())  {
		in >> set;
		udoc.append(set);
	  }
    return in;
}


/* salvare i codici delle immagini attributi case hotel ecc... */
inline QString meseBuffer( CMonths& xdata  )
{
	QByteArray bytes;
	QBuffer buffer(&bytes);
	if (!buffer.open(QIODevice::WriteOnly)) {
		return QString();
	}
	QDataStream ds(&buffer);
	/* place header */
	ds.setVersion(QDataStream::Qt_4_0);
	ds << (quint32)CMonths::MAGICNUMBER;
	ds << (quint32)CMonths::VERSION;
  ds << xdata;
	buffer.close();
	return bytes.toBase64();
}

/* decoded base64 stream to put on mysql row , file or network streams */
inline CMonths OmeseBuffer( const QString datastream_base64   )
{
	QByteArray xcode("");
	xcode.append(datastream_base64);
  
  CMonths set;
	quint32 magic, version;
  
  QByteArray bytes(QByteArray::fromBase64(xcode));
	   /* decoded base64 string to QByteArray */
	QBuffer buffer(&bytes);
	if (!buffer.open(QIODevice::ReadOnly)) {
		return set;
	}
	QDataStream ds(&buffer);
	/* place header */
	ds.setVersion(QDataStream::Qt_4_0);
	ds >> magic;
	if ( (quint32)CMonths::MAGICNUMBER != magic ) {
    qDebug() << "######## MAGICNUMBER not ok  ";
		buffer.close();
		return set;
	}
	ds >> version;
	if ( (quint32)CMonths::VERSION != version ) {
		qDebug() << "######## VERSION not ok  ";
		buffer.close();
		return set;
	}
	/* place header */
  ds >> set;
	buffer.close();
	return set;
}




class CAnno
{
  public:
  enum { MAGICNUMBER = 0xFFAAFFAA, VERSION = 5 };
  CAnno() {
  QDate current = QDate::currentDate();
  annx = current.year();
  owner = 0;
  lastupdate = QDateTime::currentDateTime();
  }
  void init( int y ) {
     save_mont.clear();
     annx = y;
     xyear = y;
    
     for (int Monthis = 1; Monthis <= 12; ++Monthis) {
       CMonths M;
               M.init(y,Monthis);
       save_mont.append(M);
     }
  
  }
  /* start current year */
  void setup()
  {
  init(annx);
  }
  operator QVariant() const {
  return QVariant::fromValue(*this);
  }
  int size() {
    return save_mont.size();
  }
  QList<CMonths> list() {
  return save_mont;
  }
  int year() const {
    return annx;
  }
  void rewrite( QList<CMonths> li )
  {
    save_mont.clear();
    for (int i=0; i<li.size(); i++) {
        CMonths dmese = li[i];
        save_mont.append(dmese);
    }
    
  }
  
  int valid_day_size()
  {
    int daten = 0;
    
    for (int i=0; i<save_mont.size(); i++) {
        CMonths dmese = save_mont[i];
        daten = dmese.count_filled() + daten;
    }
    return daten;
  }
  
  void append( CMonths d )
  {
    save_mont.append(d);
  }
  void clear() {
    return save_mont.clear();
  }
  int total()
  {
    int tt = 0;
    for (int i=0; i<save_mont.size(); i++) {
      CMonths mese = save_mont[i];
        int tz = mese.sum_day();
        tt = tz + tt;
    }
    return tt;
  }  
  void pzip()
  {
    if (save_mont.size() !=12) {
    //////setup();
    return;
    }
    data = "";
    QStringList fork;
    for (int i=0; i<save_mont.size(); i++) {
         CMonths mese = save_mont[i];
         fork.append(meseBuffer(mese));
         qDebug() << "zip  " << i;
    }
    data = fork.join("|");
    lastupdate = QDateTime::currentDateTime();
  }
  void unzip()
  {
    if (data.size() > 0) {
       QList<CMonths> mount;
       QStringList fork = data.split("|");
       /////qDebug() << "unzip   " << fork .size();
        for (int i = 0; i < fork.size(); ++i)  {
          mount.append(OmeseBuffer(fork.at(i)));
        }
        ///////qDebug() << "mount   " << mount.size();
        if (mount.size() == 12) {
        rewrite(mount);
        }
    }
  }
  
    bool operator!=( const CAnno& d )
    {
      if (lastupdate.toTime_t() != lastupdate.toTime_t() && d.owner !=owner ) {
        return true;
        } else {
        return false;
      }
        
    }
    
    CAnno operator=(  CAnno d )
    {
      //////////qDebug() << "operator=  CAnno-> annx=" << d.annx;
      d.pzip();
      annx = d.annx;
      xyear = d.xyear;
      owner = d.owner;
      data = d.data;
      web = web;
      lastupdate = d.lastupdate;
      unzip();
      return *this;
    }
  
   QList<CMonths> save_mont;
   /* vars permanent */
   int annx;
   int xyear;
   int owner;
   QString data;
   QString web;
   QDateTime lastupdate;
};




Q_DECLARE_METATYPE(CAnno);
typedef QMap<int,CAnno> AnniFatti;


/* salvare i codici delle immagini attributi case hotel ecc... */
inline QString saveAnnoBuffer( CAnno& xdata  )
{
  xdata.pzip();
	QByteArray bytes;
	QBuffer buffer(&bytes);
	if (!buffer.open(QIODevice::WriteOnly)) {
		return QString();
	}
	QDataStream ds(&buffer);
	/* place header */
	ds.setVersion(QDataStream::Qt_4_0);
	ds << (quint32)CAnno::MAGICNUMBER;
	ds << (quint32)CAnno::VERSION;
	/* place header */
	ds << xdata.annx;
	ds << xdata.xyear;
	ds << xdata.owner;
	ds << xdata.data;
  ds << xdata.web;
  ds << xdata.lastupdate;
	buffer.close();
	return bytes.toBase64();
}


/* decoded base64 stream to put on mysql row , file or network streams */
inline CAnno openAnnoBuffer( const QString datastream_base64   )
{
	QByteArray xcode("");;
	xcode.append(datastream_base64);
	
	CAnno xdata;
  CMonths set;
	quint32 magic, version;
	QByteArray bytes(QByteArray::fromBase64(xcode));   /* decoded base64 string to QByteArray */
	QBuffer buffer(&bytes);
	if (!buffer.open(QIODevice::ReadOnly)) {
		return xdata;
	}
  
	QDataStream ds(&buffer);
	/* place header */
	ds.setVersion(QDataStream::Qt_4_0);
	ds >> magic;
	if ( (quint32)CAnno::MAGICNUMBER != magic ) {
    qDebug() << "######## MAGICNUMBER not ok  ";
		buffer.close();
		return xdata;
	}
	ds >> version;
	if ( (quint32)CAnno::VERSION != version ) {
		qDebug() << "######## VERSION not ok  ";
		buffer.close();
		return xdata;
	}
	/* place header */
	ds >> xdata.annx;
	ds >> xdata.xyear;
	ds >> xdata.owner;
	ds >> xdata.data;
  ds >> xdata.web;
  xdata.unzip();
	buffer.close();
	return xdata;
}












#endif // TIMESTRUCTURE_H

